package com.binance.mbxgateway.web.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.annotation.Resource;

import com.binance.autojob.annotation.MyScheduledJob;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.support.RequestContextUtils;
import org.springframework.web.util.UriComponentsBuilder;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.binance.account.api.CountryApi;
import com.binance.account.api.SubUserApi;
import com.binance.account.vo.subuser.request.UserIdReq;
import com.binance.account.vo.user.response.GetUserResponse;
import com.binance.assetservice.api.IProductApi;
import com.binance.assetservice.vo.ProductItemVO;
import com.binance.assetservice.vo.request.product.FetchProductsRequest;
import com.binance.assetservice.vo.request.product.GetProductItemRequest;
import com.binance.assetservice.vo.response.product.FetchProductsResponse;
import com.binance.assetservice.vo.response.product.ProductItemResponse;
import com.binance.master.enums.TerminalEnum;
import com.binance.master.error.BusinessException;
import com.binance.master.error.GeneralCode;
import com.binance.master.models.APIResponse;
import com.binance.master.utils.FormatUtils;
import com.binance.master.utils.RedisCacheUtils;
import com.binance.master.utils.WebUtils;
import com.binance.mbxgateway.data.models.RuleModel;
import com.binance.mbxgateway.vo.request.order.DeleteAllOrderRequest;
import com.binance.mbxgateway.vo.request.order.DeleteOrderRequest;
import com.binance.mbxgateway.vo.request.order.DeleteOrderResponse;
import com.binance.mbxgateway.vo.request.order.PlaceOrderRequest;
import com.binance.mbxgateway.vo.response.order.PlaceOrderResponse;
import com.binance.mbxgateway.web.service.IMatchboxService;
import com.binance.mbxgateway.web.service.IOrderService;
import com.binance.mbxgateway.web.service.ITradeRuleService;
import com.binance.mbxgateway.web.utils.Constants;
import com.binance.mbxgateway.web.utils.MatchboxReturnUtils;
import com.binance.streamer.api.order.OrderApi;
import com.binance.streamer.api.request.order.QueryOpenOrderRequest;
import com.binance.streamer.api.response.openOrder.QueryOpenOrderResponse;
import com.binance.streamer.api.response.vo.OpenOrderVo;
import com.binance.sysconf.service.SysConfigVarCacheService;
import com.google.common.collect.Lists;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class OrderServiceImpl extends BaseServiceImpl implements IOrderService, SmartInitializingSingleton {
    private static final String PRICE_FILTER_CACHE_KEY_PREFIX = "percent:price";
    private static final String DEFAULT_CLIENT_TYPE = "default";
    @Autowired
    private SysConfigVarCacheService sysConfigService;
    @Resource
    private IProductApi productApi;
    @Resource
    private OrderApi orderApi;
    @Resource
    private SubUserApi subUserApi;
    @Resource
    private CountryApi countryApi;
    @Autowired
    private IMatchboxService matchboxService;
    @Autowired
    private ITradeRuleService tradeRuleService;
    @Autowired
    private RestTemplate restTemplate;
    @Value("${matchbox.rest.root.url}")
    private String restUrl;
    @Value("${matchbox.rest.root.v3url}")
    private String restV3Url;

    private static String DEFAULT_MIN_RATE = "0.2";
    private static String DEFAULT_MAX_RATE = "5";

    private static Map<String, String> errorMap = new HashMap<String, String>();
    static {
        errorMap.put("MARKET IS CLOSED", GeneralCode.ORDER_MARKET_IS_CLOSED.getCode());
        errorMap.put("INSUFFICIENT BALANCE", GeneralCode.ORDER_INSUFFICIENT_BALANCE.getCode());
        errorMap.put("TOO MANY NEW ORDERS", GeneralCode.ORDER_TOO_MANY_NEW_ORDERS.getCode());
        errorMap.put("LOT_SIZE", GeneralCode.ORDER_LOT_SIZE.getCode());
        errorMap.put("PERCENT_PRICE", GeneralCode.ORDER_PRICE_FILTER.getCode());
        errorMap.put("PRICE_FILTER", GeneralCode.ORDER_PRICE_FILTER.getCode());
        errorMap.put("MIN_NOTIONAL", GeneralCode.ORDER_MIN_NOTIONAL.getCode());
        errorMap.put("T_PLUS_SELL", GeneralCode.ORDER_T_PLUS_SELL.getCode());
        errorMap.put("MAX_POSITION", GeneralCode.ORDER_MAX_POSITION.getCode());
        errorMap.put("THIS ACTION DISABLED", GeneralCode.ORDER_THIS_ACTION_DISABLED.getCode());
        errorMap.put("MIN_MAX_", GeneralCode.ORDER_MIN_MAX.getCode());
        errorMap.put("PRICE X QTY", GeneralCode.ORDER_PRICE_X_QTY.getCode());
        errorMap.put("QTY IS UNDER THE SYMBOL'S MINIMUM QTY", GeneralCode.ORDER_QTY_UNDER_MINIMUM_QTY.getCode());
        errorMap.put("QTY IS OVER THE SYMBOL'S MAXIMUM QTY", GeneralCode.ORDER_QTY_OVER_MAXIMUM_QTY.getCode());
        errorMap.put("PRICE IS OVER THE SYMBOL'S MAXIMUM PRICE", GeneralCode.ORDER_PRICE_OVER_MAXIMUM_PRICE.getCode());
        errorMap.put("PRICE IS UNDER THE SYMBOL'S MINIMUM PRICE", "order.price_under_minimum_price");
        errorMap.put("MARKET_CLOSED", GeneralCode.ORDER_MARKET_CLOSED.getCode());
        errorMap.put("Price * QTY is zero or less.", GeneralCode.ORDER_LESS_ZERO.getCode());
        errorMap.put("INVALID QUANTITY.", GeneralCode.ORDER_INVALID_QUANTITY.getCode());
        errorMap.put("MAX_NUM_ALGO_ORDERS", GeneralCode.ORDER_MAX_NUM_ALGO_ORDERS.getCode());
    }

    @MyScheduledJob(cron = "0 0/2 * * * ?", author = "wangxiao", alarmEmail = "louis.wang@binance.com",
            jobDesc = "每隔2分钟执行一次initPriceLimit")
    public void initPriceLimit() {
        List<String> symbols = null;
        try {
            symbols = this.getAPIRequestResponse(this.productApi.getVisibleSymbols(this.newVoidAPIRequest()));
        } catch (Exception e) {
            log.error("获取所有产品出错：", e);
            return;
        }
        if (symbols != null) {
            for (String symbol : symbols) {
                ProductItemResponse response = null;
                try {
                    GetProductItemRequest body = new GetProductItemRequest();
                    body.setSymbol(symbol);
                    response = this.getAPIRequestResponse(this.productApi.getProductItem(this.newAPIRequest(body)));
                } catch (Exception e) {
                    log.error("获取产品出错：{},{}", symbol, e);
                    continue;
                }
                if (CollectionUtils.isEmpty(response.getProductItems())) {
                    continue;
                }
                try {
                    ProductItemVO product = response.getProductItems().get(0);
                    UriComponentsBuilder builder = UriComponentsBuilder
                            .fromHttpUrl(String.format("%s/avgPrice", restV3Url)).queryParam("symbol", symbol);
                    log.info("initPriceLimit: the url is {}", builder.build().toUri());
                    String avgPrice = restTemplate.getForObject(builder.build().toUri(), String.class);
                    JSONObject priceObj = JSONObject.parseObject(avgPrice);
                    String minPriceRate = StringUtils.defaultIfBlank(this.sysConfigService.getValue("min_price_rate"),
                            DEFAULT_MIN_RATE);
                    String maxPriceRate = StringUtils.defaultIfBlank(this.sysConfigService.getValue("max_price_rate"),
                            DEFAULT_MAX_RATE);
                    // 最小价格波动
                    BigDecimal tickSize = product.getTickSize();
                    // 最小数量波动
                    int stepSize = product.getStepSize().stripTrailingZeros().scale();
                    int tickSizeCount = tickSize.stripTrailingZeros().scale();

                    BigDecimal maxPrice =
                            new BigDecimal(priceObj.getDouble("price")).multiply(new BigDecimal(maxPriceRate));
                    BigDecimal minPrice =
                            new BigDecimal(priceObj.getDouble("price")).multiply(new BigDecimal(minPriceRate));
                    Map<String, Object> priceFilterMap = new HashMap<String, Object>();
                    priceFilterMap.put("updateTime", System.currentTimeMillis());
                    priceFilterMap.put("symbol", symbol);
                    priceFilterMap.put("maxrate", maxPriceRate);
                    priceFilterMap.put("minrate", minPriceRate);
                    priceFilterMap.put("stepSize", stepSize);
                    priceFilterMap.put("price", priceObj.getDouble("price"));
                    priceFilterMap.put("tickSize", FormatUtils.getPriceNumericFormatter().format(tickSize));
                    priceFilterMap.put("maxPrice",
                            maxPrice.setScale(tickSizeCount, BigDecimal.ROUND_CEILING).toPlainString());
                    priceFilterMap.put("minPrice",
                            minPrice.setScale(tickSizeCount, BigDecimal.ROUND_CEILING).toPlainString());
                    RedisCacheUtils.set(symbol, priceFilterMap, 3 * 3600, PRICE_FILTER_CACHE_KEY_PREFIX);
                    log.info("The priceFilterMap is : {}", JSON.toJSONString(priceFilterMap));
                } catch (HttpStatusCodeException e) {
                    HttpStatusCodeException ee = (HttpStatusCodeException) e;
                    log.error("更新初始化下单价格限制出错(HttpStatusCodeException)：{},{},{}", symbol, ee.getResponseBodyAsString(),
                            ee);
                } catch (Exception e) {
                    log.error("更新初始化下单价格限制出错：", e);
                }
            }
        }
    }

    private void validatePlaceOrderRequest(PlaceOrderRequest body) {
        if (body.getQuantity() == null) {
            throw new BusinessException(GeneralCode.SYS_VALID);
        }
        if (body.getSymbol() == null) {
            throw new BusinessException(GeneralCode.SYS_VALID);
        }
        if (body.getSide() == null) {
            throw new BusinessException(GeneralCode.SYS_VALID);
        }
        if ("LIMIT".equals(body.getType())) {
            // 限价单
            if (body.getPrice() == null) {
                throw new BusinessException(GeneralCode.SYS_VALID);
            }
        }
        if ("MARKET".equals(body.getType())) {
            // 市价单
        }
        if ("TAKE_PROFIT_LIMIT".equals(body.getType()) || "STOP_LOSS_LIMIT".equals(body.getType())) {
            // 止盈止损单
            if (body.getPrice() == null) {
                throw new BusinessException(GeneralCode.SYS_VALID);
            }
            if (body.getStopPrice() == null) {
                throw new BusinessException(GeneralCode.SYS_VALID);
            }
        }
    }

    @Override
    public PlaceOrderResponse placeOrder(PlaceOrderRequest body) throws Exception {
        log.info(String.format("private/order userId:%s symbol:%s side:%s price:%f quantity:%f IP:%s", body.getUserId(),
                body.getSymbol(), body.getSide(), body.getPrice(), body.getQuantity(), WebUtils.getRequestIp()));
        this.validatePlaceOrderRequest(body);
        if (StringUtils.equals("1", this.sysConfigService.getValue(Constants.SYSTEM_MAINTENANCE))) {
            throw new BusinessException(GeneralCode.SYS_MAINTENANCE);
        }
        // 若为子账户，子账户须被母账户启用方可交易
        UserIdReq userIdReq = new UserIdReq();
        userIdReq.setUserId(Long.parseLong(body.getUserId()));
        Boolean checkResp =
                this.getAPIRequestResponse(this.subUserApi.notSubUserOrIsEnabledSubUser(this.newAPIRequest(userIdReq)));
        if (!BooleanUtils.isTrue(checkResp)) {
            throw new BusinessException(GeneralCode.SUB_USER_NOT_ENABLED);
        }
        // 若为黑名单用户则不允许交易
        APIResponse<Boolean> response = this.countryApi.isUserInBlacklist(Long.parseLong(body.getUserId()));
        Boolean inBlackList = this.getAPIRequestResponse(response);
        if (BooleanUtils.isTrue(inBlackList)) {
            throw new BusinessException(GeneralCode.BLACKLISTUSER_NOT_ENABLED, response.getSubData(), new Object[] {});
        }
        return this.internalPlaceOrder(body.getSymbol(), body.getSide(), body.getType(), body.getQuantity(),
                body.getPrice(), body.getStopPrice(), body.getOrderId(), body.getUserId(), body.getActive());
    }

    private PlaceOrderResponse internalPlaceOrder(String symbol, String side, String type, Double quantity,
            Double price, Double stopPrice, Long orderId, String userId, Boolean active) throws Exception {
        if (StringUtils.isNotBlank(type) && type.toUpperCase().contains("LIMIT") && price == null) {
            throw new BusinessException(GeneralCode.PRODUCT_PRICE_EMPTY);
        }
        // 检查产品是否存在
        GetProductItemRequest body = new GetProductItemRequest();
        body.setSymbol(symbol);
        ProductItemResponse productItemResponse =
                this.getAPIRequestResponse(this.productApi.getProductItem(this.newAPIRequest(body)));
        if (productItemResponse == null || productItemResponse.getProductItems().isEmpty()) {
            throw new BusinessException(GeneralCode.SYS_ERROR, "产品不存在");
        }
        GetUserResponse getUserResponse = this.getCheckedUser(userId);

        String timeInForce = null, strPrice = null;
        if (StringUtils.isNotBlank(type) && type.toUpperCase().contains("LIMIT")) {
            if (BooleanUtils.isNotTrue(active)) {
                timeInForce = "GTC";
            } else {
                timeInForce = "IOC";
            }
            strPrice = FormatUtils.getAssetNumericFormatter().format(price);
        }
        String stopPriceStr = null;
        if (stopPrice != null) {
            stopPriceStr = FormatUtils.getAssetNumericFormatter().format(stopPrice);
        }
        Long targetOrderId = null;
        if (orderId != null) {
            strPrice = FormatUtils.getPriceNumericFormatter().format(price);
            targetOrderId = orderId;
        }
        String newClientOrderId = getNewClientOrderId();
        try {
            String jsonStr = this.matchboxService.postOrder(getUserResponse.getUserInfo().getTradingAccount(),
                    FormatUtils.getAssetNumericFormatter().format(quantity), side.toUpperCase(), symbol, type, null,
                    null, newClientOrderId.length() > 36 ? newClientOrderId.substring(0, 36) : newClientOrderId, null,
                    strPrice, stopPriceStr, targetOrderId, timeInForce);
            return MatchboxReturnUtils.getMbxValue(jsonStr, PlaceOrderResponse.class);
        } catch (HttpStatusCodeException e) {
            String responseString = e.getResponseBodyAsString();
            log.info("Failed to place order: {}", responseString);
            String error =
                    errorTranslate(responseString, symbol, userId, price, productItemResponse.getProductItems().get(0));
            // is like {"msg":"order.min_price","code":-1013,"objs":" 7.4"}
            log.info("After errorTranslate,Failed to place order:{}", error);
            JSONObject jsonError = JSON.parseObject(error);
            GeneralCode errorCode = GeneralCode.findByCode(jsonError.getString("msg"));
            if (errorCode == null) {
                log.error("Failed to place order: {},{}", responseString, jsonError);
                throw new BusinessException(GeneralCode.PLACE_ORDER_ERROR, new Object[] {jsonError.getString("msg")});
                // throw new Exception(String.format("Failed to place order: {},{}", responseString, jsonError));
            }
            if (jsonError.containsKey("objs")) {
                Object objs = jsonError.get("objs");
                if (objs instanceof Object[]) {
                    throw new BusinessException(errorCode, (Object[]) objs);
                } else if (objs instanceof JSONArray) {
                    throw new BusinessException(errorCode, ((JSONArray) objs).toArray());
                } else {
                    throw new BusinessException(errorCode, new Object[] {objs});
                }
            } else {
                throw new BusinessException(errorCode);
            }
        }
    }


    // public static void main(String[] args) {
    // JSONObject errJson = new JSONObject();
    // errJson.put("objs", "" + "abc");
    // JSONObject jsonError = JSON.parseObject(errJson.toString());
    // if (jsonError.containsKey("objs")) {
    // Object objs = jsonError.get("objs");
    // if (objs instanceof Object[]) {
    // System.out.println("===1");
    // } else if (objs instanceof JSONArray) {
    // System.out.println("===2");
    // } else {
    // System.out.println("===3");
    // }
    // } else {
    // System.out.println("===4");
    // }
    // }

    private String getI18nString(GeneralCode code) {
        MessageSource messageSource = WebUtils.getApplicationContext().getBean(MessageSource.class);
        Locale locale = RequestContextUtils.getLocale(WebUtils.getHttpServletRequest());
        String strCode = GeneralCode.class.getName() + "." + code;
        try {
            return messageSource.getMessage(new DefaultMessageSourceResolvable(strCode), locale);
        } catch (NoSuchMessageException e) {
            return code.getCode() + "/" + code.getMessage();
        }
    }

    private String getNewClientOrderId() {
        String newClientOrderId = null;
        TerminalEnum terminal = WebUtils.getTerminal();
        if (terminal == null) {
            newClientOrderId = DEFAULT_CLIENT_TYPE;
        } else {
            newClientOrderId = terminal.getCode();
        }
        if (StringUtils.equals("android", newClientOrderId)) {
            newClientOrderId = "and";
        }
        newClientOrderId =
                (newClientOrderId + "_" + com.binance.master.utils.StringUtils.uuid()).replaceAll("\\s*", "");
        return newClientOrderId.length() > 36 ? newClientOrderId.substring(0, 36) : newClientOrderId;
    }

    @Override
    public DeleteOrderResponse deleteOrder(DeleteOrderRequest body) throws Exception {
        if (StringUtils.equals("1", this.sysConfigService.getValue(Constants.SYSTEM_MAINTENANCE))) {
            throw new BusinessException(GeneralCode.SYS_MAINTENANCE);
        }
        if (body.getSymbols().size() != body.getOrderIds().size()) {
            throw new BusinessException(GeneralCode.ILLEGAL_PARAM);
        }
        GetUserResponse getUserResponse = this.getCheckedUser(body.getUserId());
        List<String> symbols = body.getSymbols();
        List<String> orderIds = body.getOrderIds();
        return this.delOrder(getUserResponse, symbols, orderIds, true);
    }

    private DeleteOrderResponse addDeleteOrderResponse(DeleteOrderResponse response1, DeleteOrderResponse response2) {
        DeleteOrderResponse resp = new DeleteOrderResponse();
        resp.getCorrects().addAll(response1.getCorrects());
        resp.getErrors().addAll(response1.getErrors());
        resp.getCorrects().addAll(response2.getCorrects());
        resp.getErrors().addAll(response2.getErrors());
        return resp;
    }

    private DeleteOrderResponse delOrder(GetUserResponse getUserResponse, List<String> symbols, List<String> orderIds,
            Boolean force) {
        DeleteOrderResponse response = new DeleteOrderResponse();
        for (int i = 0; i < symbols.size(); i++) {
            String symbol = symbols.get(i);
            String orderId = orderIds.get(i);
            String newClientOrderId = this.getNewClientOrderId();
            try {
                this.matchboxService.deleteOrder(getUserResponse.getUserInfo().getTradingAccount(), symbol, force,
                        newClientOrderId, orderId, null);
                response.addCorrect(orderId, symbol, this.getI18nString(GeneralCode.ORDER_TRADE_CANCEL_SUCCESS));
            } catch (HttpStatusCodeException e) {
                // JSONObject result = new JSONObject();
                String responseString = e.getResponseBodyAsString();
                log.error("撤单失败：{},{}", responseString, e);
                JSONObject obj = JSON.parseObject(responseString);
                if ("Unknown order sent.".equalsIgnoreCase(obj.get("msg").toString())) {
                    log.warn("订单状态过期:{}-{}", symbol, orderId);
                    JSONObject order = this.getOrderById(symbol, Long.parseLong(orderId));
                    if (order != null) {
                        String status = order.getString("status");
                        if ("FILLED".equals(status)) {
                            response.addError(orderId, symbol, this.getI18nString(GeneralCode.ORDER_TRADE_SUCCESS));
                            //
                            // result.put("msg", GeneralCode.ORDER_TRADE_SUCCESS.getCode());
                            // result.put("orderInfo", orderId+"/"+symbol);
                            // errorResultInfo.add(result);
                            // return result;
                        } else if ("REJECTED".equals(status)) {
                            response.addError(orderId, symbol, this.getI18nString(GeneralCode.ORDER_TRADE_REFUSE));
                            // result.put("msg", GeneralCode.ORDER_TRADE_REFUSE.getCode());
                            // result.put("orderInfo", orderId+"/"+symbol);
                            // errorResultInfo.add(result);
                            // return result;
                        } else if ("EXPIRED".equals(status)) {
                            response.addError(orderId, symbol, this.getI18nString(GeneralCode.ORDER_TRADE_OVER_TIME));
                            // result.put("msg", GeneralCode.ORDER_TRADE_OVER_TIME.getCode());
                            // result.put("orderInfo", orderId+"/"+symbol);
                            // errorResultInfo.add(result);
                            // return result;
                        } else if ("CANCELED".equals(status)) {
                            response.addError(orderId, symbol, this.getI18nString(GeneralCode.ORDER_TRADE_CANCEL));
                            // result.put("msg", GeneralCode.ORDER_TRADE_CANCEL.getCode());
                            // result.put("orderInfo", orderId+"/"+symbol);
                            // errorResultInfo.add(result);
                            // return result;
                        }
                    }
                } else if ("MARKET_CLOSED".equalsIgnoreCase(obj.get("msg").toString())) {
                    response.addError(orderId, symbol, this.getI18nString(GeneralCode.ORDER_MARKET_CLOSED));
                    // result.put("msg", GeneralCode.ORDER_MARKET_CLOSED.getCode());
                    // result.put("orderInfo", orderId+"/"+symbol);
                    // errorResultInfo.add(result);
                    // return result;
                }
            }
        }
        return response;
        // result.put("success", "true");
        // result.put("msg", GeneralCode.ORDER_TRADE_CANCEL_SUCCESS.getCode());
        // return result;
    }


    private JSONObject getOrderById(String symbol, Long orderId) {
        try {
            String orderString = this.matchboxService.getOrder(symbol, orderId, null);
            JSONObject obj = JSON.parseObject(orderString);
            if (obj.containsKey("orderId")) {
                return obj;
            }
        } catch (HttpStatusCodeException e) {
            String responseString = e.getResponseBodyAsString();
            log.warn("Failed to fetch order, details: {}", responseString);
        } catch (Exception e) {
            log.error(String.format("Failed to fetch order"), e);
        }
        return null;
    }

    @Override
    public DeleteOrderResponse deleteAllOrder(DeleteAllOrderRequest body) throws Exception {
        if (StringUtils.equals("1", this.sysConfigService.getValue(Constants.SYSTEM_MAINTENANCE))) {
            throw new BusinessException(GeneralCode.SYS_MAINTENANCE);
        }
        DeleteOrderResponse response = new DeleteOrderResponse();
        GetUserResponse getUserResponse = this.getCheckedUser(body.getUserId());
        QueryOpenOrderRequest queryOpenOrderRequest = new QueryOpenOrderRequest();
        queryOpenOrderRequest.setUserId(getUserResponse.getUser().getUserId());
        queryOpenOrderRequest.setSymbol(body.getSymbol());
        QueryOpenOrderResponse queryOpenOrderResponse =
                this.getAPIRequestResponse(this.orderApi.queryOpenOrder(this.newAPIRequest(queryOpenOrderRequest)));
        if (queryOpenOrderResponse == null || queryOpenOrderResponse.getOpenOrderList() == null
                || queryOpenOrderResponse.getOpenOrderList().isEmpty()) {
            throw new BusinessException(GeneralCode.SYS_NOT_EXIST);
        }
        boolean notFound = true;
        for (OpenOrderVo order : queryOpenOrderResponse.getOpenOrderList()) {

            // if (StringUtils.equals(order.getType(), body.getType()) || StringUtils.equals("ALL",
            // body.getType())
            // || StringUtils.isBlank(body.getType())
            // || (StringUtils.equals("STOP_LIMIT", body.getType()) &&
            // ("STOP_LOSS_LIMIT".equals(order.getType())
            // || "TAKE_PROFIT_LIMIT".equals(order.getType())))) {
            // }
            if (StringUtils.isBlank(body.getType()) || StringUtils.equals(order.getType(), body.getType())
                    || ("STOP_LIMIT".equals(body.getType()) && ("STOP_LOSS_LIMIT".equals(order.getType())
                            || "TAKE_PROFIT_LIMIT".equals(order.getType())))) {
                notFound = false;
                DeleteOrderResponse resp = this.delOrder(getUserResponse, Lists.newArrayList(order.getSymbol()),
                        Lists.newArrayList(order.getOrderId().toString()), true);
                response = this.addDeleteOrderResponse(response, resp);
            }
        }
        if (notFound) {
            log.warn("条件没有满足，没有实质进行撤单处理。条件是：{}", body);
        }
        return response;
    }

    private String errorTranslate(String error, String symbol, String userId, Double price, ProductItemVO productItem) {
        String uppercase = error.toUpperCase();
        for (String key : errorMap.keySet()) {
            if (uppercase.contains(key)) {
                if ("LOT_SIZE".equals(key) || "MIN_NOTIONAL".equals(key)
                        || "QTY IS OVER THE SYMBOL'S MAXIMUM QTY".equals(key)
                        || "PRICE IS OVER THE SYMBOL'S MAXIMUM PRICE".equals(key)) {
                    JSONObject errJson = JSON.parseObject(error);
                    errJson.put("objs", getRuleObject(symbol));
                    error = errJson.toString();
                }
                if ("MAX_NUM_ALGO_ORDERS".equals(key)) {
                    JSONObject errJson = JSON.parseObject(error);
                    error = errJson.toString();
                }
                if ("PERCENT_PRICE".equals(key)) {
                    Map<String, Object> priceFilter =
                            RedisCacheUtils.get(symbol, Map.class, PRICE_FILTER_CACHE_KEY_PREFIX);
                    if (priceFilter == null) {
                        this.initPriceLimit();
                        priceFilter = RedisCacheUtils.get(symbol, Map.class, PRICE_FILTER_CACHE_KEY_PREFIX);
                    }
                    BigDecimal tickSize = new BigDecimal(priceFilter.get("tickSize").toString());
                    BigDecimal a = new BigDecimal(String.valueOf(price)).divide(tickSize, 8, RoundingMode.CEILING);
                    if (new BigDecimal(a.intValue()).compareTo(a) == 0) {
                        if (price > Double.parseDouble(priceFilter.get("maxPrice").toString())) {
                            errorMap.put("PERCENT_PRICE", GeneralCode.ORDER_MAX_PRICE.getCode());
                            JSONObject errJson = JSON.parseObject(error);
                            errJson.put("objs", priceFilter.get("maxPrice").toString());
                            log.info("价格限制之maxPirce:{},{},{}", priceFilter.get("maxPrice").toString(), symbol, price);
                            error = errJson.toString();
                        } else if (price < Double.parseDouble(priceFilter.get("minPrice").toString())) {
                            errorMap.put("PERCENT_PRICE", GeneralCode.ORDER_MIN_PRICE.getCode());
                            JSONObject errJson = JSON.parseObject(error);
                            errJson.put("objs", priceFilter.get("minPrice").toString());
                            log.info("价格限制之minPrice:{},{},{}", priceFilter.get("minPrice").toString(), symbol, price);
                            error = errJson.toString();
                        } else {
                            JSONObject errJson = JSON.parseObject(error);
                            error = errJson.toString();
                        }
                    } else {
                        errorMap.put("PERCENT_PRICE", GeneralCode.ORDER_TICK_SIZE_LIMIT.getCode());
                        JSONObject errJson = JSON.parseObject(error);
                        errJson.put("objs", priceFilter.get("tickSize").toString());
                        log.info("价格限制之tickSize:{},{},{}", priceFilter.get("tickSize").toString(), symbol, price);
                        error = errJson.toString();
                    }
                }
                if ("PRICE_FILTER".equals(key)) {
                    Map<String, Object> priceFilter =
                            RedisCacheUtils.get(symbol, Map.class, PRICE_FILTER_CACHE_KEY_PREFIX);
                    if (priceFilter == null) {
                        this.initPriceLimit();
                        priceFilter = RedisCacheUtils.get(symbol, Map.class, PRICE_FILTER_CACHE_KEY_PREFIX);
                    }
                    errorMap.put("PRICE_FILTER", GeneralCode.ORDER_TICK_SIZE_LIMIT.getCode());
                    JSONObject errJson = JSON.parseObject(error);
                    errJson.put("objs", priceFilter.get("tickSize").toString());
                    log.info("价格限制之tickSize:{},{},{}", priceFilter.get("tickSize").toString(), symbol, price);
                    error = errJson.toString();
                }
                return error.replaceAll("(?i)\"msg\":\"[^\"]*\"", "\"msg\":\"" + errorMap.get(key) + "\"");
            }
        }
        return error;
    }

    private String[] getRuleObject(String symbol) {
        try {
            RuleModel ruleItem = this.tradeRuleService.getRuleBySymbol(symbol);
            DecimalFormat df = new DecimalFormat("#");
            df.setMinimumIntegerDigits(1);
            df.setMaximumFractionDigits(8);
            String[] strings =
                    new String[] {ruleItem.getMinNotional() == null ? "0" : df.format(ruleItem.getMinNotional()),
                            ruleItem.getMaxTradeValue() == null ? "0" : df.format(ruleItem.getMaxTradeValue()),
                            ruleItem.getMaxPrice() == null ? "0" : df.format(ruleItem.getMaxPrice()),
                            ruleItem.getMinTrade() == null ? "0" : df.format(ruleItem.getMinTrade()),
                            ruleItem.getMinPrice() == null ? "0" : df.format(ruleItem.getMinPrice())};
            return strings;
        } catch (Exception e) {
            log.error("get Rule By Symbol Error", e);
            return new String[] {"0", "0", "0", "0", "0"};
        }
    }

    @Override
    public void afterSingletonsInstantiated() {}
}
